/*
 * Copyright 2019 NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "littlevgl_support.h"
#include "peripherals.h"
#include "lvgl.h"

#include "board.h"
#include "fsl_elcdif.h"
#include "fsl_lpi2c.h"
#include "fsl_gpio.h"
#include "fsl_ft5406_rt.h"
#include "fsl_debug_console.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/

/*******************************************************************************
 * Prototypes
 ******************************************************************************/
//static void DEMO_InitLcd(void);
//static void DEMO_InitLcdClock(void);
//static void DEMO_InitLcdBackLight(void);

static void DEMO_FlushDisplay(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);

static void DEMO_InitTouch(void);
static bool DEMO_ReadTouch(lv_indev_drv_t * indev_drv, lv_indev_data_t *data);

/*******************************************************************************
 * Variables
 ******************************************************************************/
static volatile bool s_framePending;
static ft5406_rt_handle_t touchHandle;
/*******************************************************************************
 * Code
 ******************************************************************************/
void lv_port_disp_init(void)
{
    /*-------------------------
     * Initialize your display
     * -----------------------*/
	DEMO_InitLcdBackLight();
    DEMO_InitLcd();

    /*-----------------------------------
     * Register the display in LittlevGL
     *----------------------------------*/

    lv_disp_drv_t disp_drv;      /*Descriptor of a display driver*/
    lv_disp_drv_init(&disp_drv); /*Basic initialization*/

    /*Set up the functions to access to your display*/
	static lv_disp_buf_t disp_buf;
    memset((void *)DEMO_BUFFER0_ADDR, 0, LCD_WIDTH * LCD_HEIGHT * LCD_FB_BYTE_PER_PIXEL*2);
    memset((void *)DEMO_BUFFER1_ADDR, 0, LCD_WIDTH * LCD_HEIGHT * LCD_FB_BYTE_PER_PIXEL*2);
    lv_disp_buf_init(&disp_buf, DEMO_BUFFER0_ADDR, DEMO_BUFFER1_ADDR, LCD_WIDTH * LCD_HEIGHT * LCD_FB_BYTE_PER_PIXEL);
    disp_drv.buffer = &disp_buf;

    disp_drv.hor_res = LCD_WIDTH;
    disp_drv.ver_res = LCD_HEIGHT;

    /*Used in buffered mode (LV_VDB_SIZE != 0  in lv_conf.h)*/
    disp_drv.flush_cb = DEMO_FlushDisplay;

    /*Finally register the driver*/
    lv_disp_drv_register(&disp_drv);
}

void LCD_IRQHandler(void)
{
    uint32_t intStatus = ELCDIF_GetInterruptStatus(LCDIF);

    ELCDIF_ClearInterruptStatus(LCDIF, intStatus);

    if (s_framePending)
    {
        if (intStatus & kELCDIF_CurFrameDone)
        {
            s_framePending = false;
        }
     }
     SDK_ISR_EXIT_BARRIER;
}


#define LCD_DISP_GPIO     GPIO1
#define LCD_DISP_GPIO_PIN 2
/* Back light. */
#define LCD_BL_GPIO     GPIO2
#define LCD_BL_GPIO_PIN 31
void DEMO_InitLcdBackLight(void)
{
    gpio_pin_config_t config = {
        kGPIO_DigitalOutput,
        0,
        kGPIO_NoIntmode,
    };

    /* Backlight. */
    config.outputLogic = 1;
    GPIO_PinInit(LCD_BL_GPIO, LCD_BL_GPIO_PIN, &config);
}

#define BOARD_LCDIF_PANEL_WIDTH	LCD_WIDTH
#define BOARD_LCDIF_PANEL_HEIGHT LCD_HEIGHT
//#define EXT_BUFFER0_ADDR (0x80000000U)

elcdif_rgb_mode_config_t BOARD_LCDIF_rgbConfig = {
  .panelWidth = BOARD_LCDIF_PANEL_WIDTH,
  .panelHeight = BOARD_LCDIF_PANEL_HEIGHT,
  .hsw = 41,
  .hfp = 4,
  .hbp = 8,
  .vsw = 10,
  .vfp = 4,
  .vbp = 2,
  .polarityFlags = (kELCDIF_VsyncActiveLow | kELCDIF_HsyncActiveLow | kELCDIF_DataEnableActiveHigh | kELCDIF_DriveDataOnRisingClkEdge),
  .bufferAddr = NULL,
  .pixelFormat = kELCDIF_PixelFormatRGB565,
  .dataBus = kELCDIF_DataBus16Bit
};
void DEMO_InitLcd(void) {
	uint16_t *t;
	t=DEMO_BUFFER0_ADDR;
	memset(t, 0xAA, BOARD_LCDIF_PANEL_WIDTH * BOARD_LCDIF_PANEL_HEIGHT *2);
	t[0]=0xAA;
	BOARD_LCDIF_rgbConfig.bufferAddr = t;

	/* RGB mode initialization */
	ELCDIF_RgbModeInit(LCDIF, &BOARD_LCDIF_rgbConfig);
    ELCDIF_RgbModeStart(LCDIF);
	/* Enable interrupts */
//	ELCDIF_EnableInterrupts(LCDIF, (kELCDIF_CurFrameDoneInterruptEnable));
	/* Enable interrupt LCDIF_IRQn request in the NVIC */
//	EnableIRQ(LCDIF_IRQn);
}

/* Flush the content of the internal buffer the specific area on the display
 * You can use DMA or any hardware acceleration to do this operation in the background but
 * 'lv_disp_flush_ready()' has to be called when finished*/
static void DEMO_FlushDisplay(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
    /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
    DCACHE_CleanInvalidateByRange((uint32_t)color_p, BOARD_LCDIF_PANEL_WIDTH * BOARD_LCDIF_PANEL_HEIGHT *2);

    ELCDIF_SetNextBufferAddr(LCDIF, (uint32_t)color_p);

    s_framePending = true;

    /* IMPORTANT!!!
     * Inform the graphics library that you are ready with the flushing*/
    lv_disp_flush_ready(disp_drv);
}

void lv_port_indev_init(void)
{
    lv_indev_drv_t indev_drv;

    /*------------------
     * Touchpad
     * -----------------*/

    /*Initialize your touchpad */
    DEMO_InitTouch();

    /*Register a touchpad input device*/
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = DEMO_ReadTouch;
    lv_indev_drv_register(&indev_drv);
}

/*Initialize your touchpad*/
static void DEMO_InitTouch(void)
{
    status_t status;

    lpi2c_master_config_t masterConfig = {0};

    /*Clock setting for LPI2C*/
    CLOCK_SetMux(kCLOCK_Lpi2cMux, 0);
    CLOCK_SetDiv(kCLOCK_Lpi2cDiv, 5);

    /*
     * masterConfig.debugEnable = false;
     * masterConfig.ignoreAck = false;
     * masterConfig.pinConfig = kLPI2C_2PinOpenDrain;
     * masterConfig.baudRate_Hz = 100000U;
     * masterConfig.busIdleTimeout_ns = 0;
     * masterConfig.pinLowTimeout_ns = 0;
     * masterConfig.sdaGlitchFilterWidth_ns = 0;
     * masterConfig.sclGlitchFilterWidth_ns = 0;
     */
    LPI2C_MasterGetDefaultConfig(&masterConfig);

    /* Change the default baudrate configuration */
    masterConfig.baudRate_Hz = 100000U;

    /* Initialize the LPI2C master peripheral */
    LPI2C_MasterInit(LPI2C1, &masterConfig, ((CLOCK_GetFreq(kCLOCK_Usb1PllClk) / 8) / (5 + 1U)));

    /* Initialize touch panel controller */
    status = FT5406_RT_Init(&touchHandle, LPI2C1);
    if (status != kStatus_Success)
    {
        PRINTF("Touch panel init failed\n");
        assert(0);
    }
}

/* Will be called by the library to read the touchpad */
//static bool DEMO_ReadTouch(lv_indev_data_t *data)
static bool DEMO_ReadTouch(lv_indev_drv_t * indev_drv, lv_indev_data_t *data)
{
    touch_event_t touch_event;
    static int touch_x = 0;
    static int touch_y = 0;

    data->state = LV_INDEV_STATE_REL;

    if (kStatus_Success == FT5406_RT_GetSingleTouch(&touchHandle, &touch_event, &touch_x, &touch_y))
    {
        if ((touch_event == kTouch_Down) || (touch_event == kTouch_Contact))
        {
            data->state = LV_INDEV_STATE_PR;
        }
    }

    /*Set the last pressed coordinates*/
    data->point.x = touch_y;
    data->point.y = touch_x;

    /*Return `false` because we are not buffering and no more data to read*/
    return false;
}
